function [Vstar_final, preY, Ub_final, Bb_final, Vb_final] = DSNMF(X,Y,opts)
%%%
k = length(unique(Y));  % class number
n = length(Y);          % sample number
 view = length(X);      % view number 

p=opts.p;
alpha=opts.alpha;
beta=opts.beta;
gamma=opts.gamma;
mu=opts.mu;
mu2=opts.mu2;
sigma=opts.sigma;

per=opts.per;
Times=opts.randtimes;
maxIter=opts.maxIter;

%%%%%%% Generate Supervisory Information %%%%%%%
[Z,testlabel,indices,~] = randomSelectLabeledData(Y,per);
A = zeros(1,n);
A(indices) = 1;
A = sparse(diag(A));
[~, encodeY] = initializeKandV(indices,Z,Y);
%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%% Generate Geometrical Structure %%%%%%%%
W = cell(1,view);
D = cell(1,view);
L = cell(1,view);
W01 = cell(1,view);

for i=1:view
    [W01{i}, W{i}] = constructW_hyper(X{i},p);
    W{i} = reviseHyperW(W{i},Z,mu2);
    D{i} = diag(sum(W{i},2));
    L{i} = D{i} - W{i};    
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%% Learning Procedures %%%%
tryNo=0;
obj=1e+150;
onek1 = ones(k,1);
onen1 = ones(n,1);
%%%
while tryNo < Times 
    tryNo = tryNo+1;
    
    %%%%%%% Initialize Ub{i}, Bb{i} and Vb %%%%%%%%%
    Ub = cell(1,view);
    Bb = cell(1,view);
    Vb = cell(1,view);
    for i=1:view
        Ub{i} = rand(size(X{i},2),k);
        Bb{i} = rand(k,k);
        Vb{i} = rand(n,k);
    end
    Vstar = rand(n,k);
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    
    %%%%%% Recording the Objective Function Value for Each Updating %%%%%%
    obj_temp_record = [];
    obj_temp = 0;
    for i=1:view
        obj_temp = obj_temp + sum(sum((X{i}'-Ub{i}*Bb{i}*Vb{i}').^2)) ...
                   + alpha*sum(sum((L{i}*Vb{i}).*Vb{i})) + beta*sum(sum(((Vb{i}-encodeY).^2).*repmat(diag(A),1,k))) ...
                   + gamma*sum(sum((Vstar-Vb{i}).^2)) + mu*sum(sum((Vb{i}*onek1-onen1).^2)) ...
                   + sigma*sum(sum(((Bb{i}')*Bb{i}-eye(k)).^2));
    end
    obj_temp_record = [obj_temp_record, obj_temp];
       
    nIter=0;
    while nIter<maxIter
        
        % update Ub{i}, Bb{i} and Vb{i}
        for i=1:view
           
            Ub_up = X{i}'*Vb{i}*Bb{i}';
            Ub_down = Ub{i}*Bb{i}*(Vb{i}')*Vb{i}*Bb{i}';            
            U = Ub{i}.*(Ub_up./max(Ub_down,1e-10));
            Ub{i} = U;
            
            Bb_up = Ub{i}'*X{i}'*Vb{i} + 2*sigma*Bb{i};
            Bb_down = (Ub{i}')*Ub{i}*Bb{i}*(Vb{i}')*Vb{i} + 2*sigma*Bb{i}*(Bb{i}')*Bb{i};
            B = Bb{i}.*(Bb_up./max(Bb_down,1e-10));
            Bb{i} = B;
            
            Vb_up = X{i}*Ub{i}*Bb{i} + alpha*W{i}*Vb{i} + beta*A*encodeY + gamma*Vstar + mu*onen1*onek1';
            Vb_down = Vb{i}*Bb{i}'*(Ub{i}')*Ub{i}*Bb{i} + alpha*D{i}*Vb{i} + beta*A*Vb{i} + gamma*Vb{i} + mu*Vb{i}*onek1*(onek1');            
            V = Vb{i}.*(Vb_up./max(Vb_down,1e-10));
            Vb{i} = V;
            
        end   
              
        % update Vstar
        sumVb=zeros(n,k);
        for i=1:view
            sumVb = sumVb + Vb{i};
        end
        Vstar = sumVb / view;
             
        nIter=nIter+1;      
        obj_temp = 0;
        for i=1:view
            obj_temp = obj_temp + sum(sum((X{i}'-Ub{i}*Bb{i}*Vb{i}').^2)) ...
                   + alpha*sum(sum((L{i}*Vb{i}).*Vb{i})) + beta*sum(sum(((Vb{i}-encodeY).^2).*repmat(diag(A),1,k))) ...
                   + gamma*sum(sum((Vstar-Vb{i}).^2)) + mu*sum(sum((Vb{i}*onek1-onen1).^2)) ...
                   + sigma*sum(sum(((Bb{i}')*Bb{i}-eye(k)).^2));
        end
        obj_temp_record = [obj_temp_record, obj_temp];

    end
    
    FR = obj_temp_record(end);

     if FR < obj
        Vb_final = Vb;
        Ub_final = Ub;
        Bb_final = Bb;
        Vstar_final = Vstar;
        obj = FR;
        obj_record = obj_temp_record;
     end

end


[~, y] = max(Vstar_final, [], 2); 
preY = bestMap(Y,y);

y(indices)=[];

Measure_result = ClusteringEvaluationMetrics(testlabel,y);
Measure_Tips = {'Acc','NMI','Purity','ARI','Recall','F-score', 'Entropy'};

for t = 1:length(Measure_Tips)
    disp(['Clustering Result on ' Measure_Tips{t} ' is ' num2str(roundn(100*Measure_result(t),-2)) '%.']);
end
disp('*****************************************************');

plot(obj_record);

end




